home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Users Group Library 1996 July
/
C-C++ Users Group Library July 1996.iso
/
listings
/
v_10_05
/
1005059a
< prev
next >
Wrap
Text File
|
1992-03-18
|
5KB
|
233 lines
/* Listing 2 */
/*****************************************************
ADCDMA.C
Routines for Data acquisition through DMA on the
Lab Master AD.
Copyright Don Bradley, 1991.
Permission is granted for used of these routines
in any manner as long as this copyright notice is
included.
Tested using Quick C 2.5 and MSC 6.0 on a
Toshiba T5200.
*****************************************************/
#include <io.h>
#include <errno.h>
#include <conio.h>
#include "dma.h"
#include "labmastr.h"
// DMA buffer
static int far *dma_buffer;
// DMA buffer index
static unsigned int dma_buff_index;
// previous DMA buffer index
static unsigned int old_dma_buff_index;
// number of conversions to collect
static long num_to_collect;
// number of conversions collected
static long num_collected;
// DMA finished flag
static int dma_finished;
// DMA channel number
static int dma_chn;
void (*process)(int);
/*****************************************************
init_adc_dma is a routine used for dma controlled
analogue voltage input.
called by:
init_adc_dma(num_chn, num_samples, *freq, dma_chn,
proc_func);
where
int num_chn # of channels to sample.
Start channel is always
chn 0. Thus chans collect
are 0 ... num_chn-1
long num_samples # of samples to collect.
A sample is the group of
channels
double *freq Frequency of sampling in Hz.
int dma_chn DMA channel number from 5-7.
void(*proc_func)(int) process function to be
called after each value is
retrieved.
*****************************************************/
int init_adc_dma(unsigned int num_chn,
long num_samples, double *freq, int dma_channel,
void (*proc_func)(int))
/*& Setup adc for dma transfer. */
{
long length;
unsigned int i;
unsigned int dma_mode;
// check for proper passed values
if (dma_channel < 5 || dma_channel > 7)
return (0);
dma_chn = dma_channel;
disable_dma(dma_chn);
disable_adc();
if(num_chn > MAX_CHANNELS)
return(FALSE);
if (*freq == 0.0)
return (FALSE);
process = proc_func;
/* create buffer for storing data in */
if(!(dma_buffer = alloc_dma_buffer(dma_chn,
ADC_DMA_BUFFER_LEN)))
return (FALSE);
clr_adc_dma_buffer();
// Frequency adjusted for number of channels.
// Next version will have a burst mode enabled.
*freq *= num_chn;
*freq = timerad(*freq);
// Readjust frequency for number of channels.
*freq /= num_chn;
// Setup the channel gain array.
for (i = 0; i < num_chn; i++) {
outp(ADC_VIRTCHAN, i);
outp(ADC_CHN_GAIN_ARRAY,
ADC_GAIN_1 | ADC_BANK_0 | i);
}
// set adc control register
outp(ADC_CONTROL, ADC_FIFO_ENABLE |
ADC_SINGLE_ENDED | ((dma_chn - 4) << 2));
outp(ADC_LASTCHAN, num_chn-1);
// Start converstions at channel zero
outp(ADC_VIRTCHAN, 0);
num_to_collect = num_chn * num_samples;
num_collected = 0L;
length = (num_to_collect < (long)ADC_DMA_BUFFER_LEN) ?
num_to_collect : (long)ADC_DMA_BUFFER_LEN;
// Setup dma transfer.
if(num_to_collect > (long)ADC_DMA_BUFFER_LEN)
dma_mode = DMA_DEMAND_MODE | DMA_ADDRESS_INC |
DMA_CONTINUOUS_ENABLE | DMA_ADC_TRANSFER;
else
dma_mode = DMA_DEMAND_MODE | DMA_ADDRESS_INC |
DMA_CONTINUOUS_DISABLE | DMA_ADC_TRANSFER;
dma(dma_chn, dma_mode, dma_buffer,
(unsigned int) length);
dma_finished = FALSE;
return (TRUE);
}
void get_next_adc_values()
/*& Returns the pointer to the next memory location,
increments appropriate buffer pointers. */
{
if(dma_buffer[dma_buff_index] == NON_ADC_VALUE)
return;
// wait until sample has been recorded
while(dma_buffer[dma_buff_index] != NON_ADC_VALUE) {
// Check for overrun by looking at last adc
// buffer location. If this location has a valid
// adc value then an overrun has occurred. An
// over run condtion will result in automatic
// termination of adc collection. To detect an
// overrun the number of samples collected will
// be less than those requested.
if(dma_buffer[old_dma_buff_index] != NON_ADC_VALUE) {
terminate_adc_dma();
return;
}
process(dma_buffer[dma_buff_index]);
// clear collected value from DMA buffer
dma_buffer[dma_buff_index] = NON_ADC_VALUE;
// increment buffer pointer
old_dma_buff_index = dma_buff_index;
if (++dma_buff_index >= ADC_DMA_BUFFER_LEN)
dma_buff_index = 0;
// Increment number of conversions collected.
// Used in automatic termination for repetitive
// sampling under DMA.
if(++num_collected >= num_to_collect) {
terminate_adc_dma();
return;
}
}
}
void terminate_adc_dma()
/* Terminates adc dma collection. */
{
disable_dma(dma_chn);
outp(ADC_CONTROL, 0);
free_dma_buffer(dma_chn);
dma_finished = TRUE;
}
void clr_adc_dma_buffer()
/*& Clears the adc buffer to a non possible value. */
{
unsigned int i;
for (i = 0; i < ADC_DMA_BUFFER_LEN; i++)
dma_buffer[i] = NON_ADC_VALUE;
dma_buff_index = 0;
old_dma_buff_index = ADC_DMA_BUFFER_LEN-1;
}
int adc_dma_done(void)
/*& Returns TRUE if all conversions are done. */
{
return(dma_finished);
}
long adc_dma_conversion_count()
/*& Returns the number of samples collected. */
{
return(num_collected);
}